/*
* Image.java
* Copyright (C) 2003
*
* $Id: Image.java,v 1.8 2004/11/10 20:35:36 cawe Exp $
*/
/*
Copyright (C) 1997-2001 Id Software, Inc.

This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

See the GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.

*/
using System;
using Defines = Suake2.UI.Defines;
using VID = Suake2.UI.client.VID;
using particle_t = Suake2.UI.client.particle_t;
using cvar_t = Suake2.UI.game.cvar_t;
using Suake2.UI.qcommon;
using image_t = Suake2.UI.render.image_t;
using Lib = Suake2.UI.util.Lib;
using Vargs = Suake2.UI.util.Vargs;
//UPGRADE_TODO: The package 'java.nio' could not be found. If it was not included in the conversion, there may be compiler issues. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1262'"
using java.nio;
using GL = net.java.games.jogl.GL;
namespace Suake2.UI.render.fastjogl
{
	
	/// <summary> Image
	/// 
	/// </summary>
	/// <author>  cwei
	/// </author>
	public abstract class Image:Main
	{
		private void  InitBlock()
		{
			for (int i = 0; i < MAX_SCRAPS; i++)
			{
				scrap_allocated[i] = new int[BLOCK_WIDTH];
			}
			for (int i2 = 0; i2 < MAX_SCRAPS; i2++)
			{
				scrap_texels[i2] = new sbyte[BLOCK_WIDTH * BLOCK_HEIGHT];
			}
			tex = Lib.newIntBuffer(512 * 256, ByteOrder.LITTLE_ENDIAN);
		}
		
		internal image_t draw_chars;
		
		internal image_t[] gltextures = new image_t[MAX_GLTEXTURES];
		
		internal int numgltextures;
		
		internal int base_textureid; // gltextures[i] = base_textureid+i
		
		internal sbyte[] intensitytable = new sbyte[256];
		
		internal sbyte[] gammatable = new sbyte[256];
		
		internal cvar_t intensity;
		
		internal int gl_solid_format = 3;
		
		internal int gl_alpha_format = 4;
		
		internal int gl_tex_solid_format = 3;
		
		internal int gl_tex_alpha_format = 4;
		
		internal int gl_filter_min = net.java.games.jogl.GL_Fields.GL_LINEAR_MIPMAP_NEAREST;
		
		internal int gl_filter_max = net.java.games.jogl.GL_Fields.GL_LINEAR;
		
		internal Image()
		{
			InitBlock();
			// init the texture cache
			for (int i = 0; i < gltextures.Length; i++)
			{
				gltextures[i] = new image_t(i);
			}
			numgltextures = 0;
		}
		
		internal override void  GL_SetTexturePalette(int[] palette)
		{
			
			//UPGRADE_ISSUE: The following fragment of code could not be parsed and was not converted. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1156'"
			assert(palette != null && palette.length == 256): int palette[256] bug;
			
			int i;
			sbyte[] temptable = new sbyte[768];
			
			if (qglColorTableEXT && gl_ext_palettedtexture.value_Renamed != 0.0f)
			{
				for (i = 0; i < 256; i++)
				{
					temptable[i * 3 + 0] = (sbyte) ((palette[i] >> 0) & 0xff);
					temptable[i * 3 + 1] = (sbyte) ((palette[i] >> 8) & 0xff);
					temptable[i * 3 + 2] = (sbyte) ((palette[i] >> 16) & 0xff);
				}
				
				gl.glColorTableEXT(net.java.games.jogl.GL_Fields.GL_SHARED_TEXTURE_PALETTE_EXT, net.java.games.jogl.GL_Fields.GL_RGB, 256, net.java.games.jogl.GL_Fields.GL_RGB, net.java.games.jogl.GL_Fields.GL_UNSIGNED_BYTE, temptable);
			}
		}
		
		internal virtual void  GL_EnableMultitexture(bool enable)
		{
			if (enable)
			{
				GL_SelectTexture(GL_TEXTURE1);
				gl.glEnable(net.java.games.jogl.GL_Fields.GL_TEXTURE_2D);
				GL_TexEnv(net.java.games.jogl.GL_Fields.GL_REPLACE);
			}
			else
			{
				GL_SelectTexture(GL_TEXTURE1);
				gl.glDisable(net.java.games.jogl.GL_Fields.GL_TEXTURE_2D);
				GL_TexEnv(net.java.games.jogl.GL_Fields.GL_REPLACE);
			}
			GL_SelectTexture(GL_TEXTURE0);
			GL_TexEnv(net.java.games.jogl.GL_Fields.GL_REPLACE);
		}
		
		internal virtual void  GL_SelectTexture(int texture)
		{
			int tmu;
			
			tmu = (texture == GL_TEXTURE0)?0:1;
			
			if (tmu == gl_state.currenttmu)
			{
				return ;
			}
			
			gl_state.currenttmu = tmu;
			
			gl.glActiveTextureARB(texture);
			gl.glClientActiveTextureARB(texture);
		}
		
		internal int[] lastmodes = new int[]{- 1, - 1};
		
		internal override void  GL_TexEnv(int mode)
		{
			
			if (mode != lastmodes[gl_state.currenttmu])
			{
				gl.glTexEnvi(net.java.games.jogl.GL_Fields.GL_TEXTURE_ENV, net.java.games.jogl.GL_Fields.GL_TEXTURE_ENV_MODE, mode);
				lastmodes[gl_state.currenttmu] = mode;
			}
		}
		
		internal override void  GL_Bind(int texnum)
		{
			
			if ((gl_nobind.value_Renamed != 0) && (draw_chars != null))
			{
				// performance evaluation option
				texnum = draw_chars.texnum;
			}
			if (gl_state.currenttextures[gl_state.currenttmu] == texnum)
				return ;
			
			gl_state.currenttextures[gl_state.currenttmu] = texnum;
			gl.glBindTexture(net.java.games.jogl.GL_Fields.GL_TEXTURE_2D, texnum);
		}
		
		internal virtual void  GL_MBind(int target, int texnum)
		{
			GL_SelectTexture(target);
			if (target == GL_TEXTURE0)
			{
				if (gl_state.currenttextures[0] == texnum)
					return ;
			}
			else
			{
				if (gl_state.currenttextures[1] == texnum)
					return ;
			}
			GL_Bind(texnum);
		}
		
		// glmode_t
		internal class glmode_t
		{
			internal System.String name;
			
			internal int minimize, maximize;
			
			internal glmode_t(System.String name, int minimize, int maximze)
			{
				this.name = name;
				this.minimize = minimize;
				this.maximize = maximze;
			}
		}
		
		//UPGRADE_NOTE: Final was removed from the declaration of 'modes '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'"
		internal static readonly glmode_t[] modes = new glmode_t[]{new glmode_t("GL_NEAREST", net.java.games.jogl.GL_Fields.GL_NEAREST, net.java.games.jogl.GL_Fields.GL_NEAREST), new glmode_t("GL_LINEAR", net.java.games.jogl.GL_Fields.GL_LINEAR, net.java.games.jogl.GL_Fields.GL_LINEAR), new glmode_t("GL_NEAREST_MIPMAP_NEAREST", net.java.games.jogl.GL_Fields.GL_NEAREST_MIPMAP_NEAREST, net.java.games.jogl.GL_Fields.GL_NEAREST), new glmode_t("GL_LINEAR_MIPMAP_NEAREST", net.java.games.jogl.GL_Fields.GL_LINEAR_MIPMAP_NEAREST, net.java.games.jogl.GL_Fields.GL_LINEAR), new glmode_t("GL_NEAREST_MIPMAP_LINEAR", net.java.games.jogl.GL_Fields.GL_NEAREST_MIPMAP_LINEAR, net.java.games.jogl.GL_Fields.GL_NEAREST), new glmode_t("GL_LINEAR_MIPMAP_LINEAR", net.java.games.jogl.GL_Fields.GL_LINEAR_MIPMAP_LINEAR, net.java.games.jogl.GL_Fields.GL_LINEAR)};
		
		//UPGRADE_NOTE: Final was removed from the declaration of 'NUM_GL_MODES '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'"
		internal static readonly int NUM_GL_MODES = modes.Length;
		
		// gltmode_t
		internal class gltmode_t
		{
			internal System.String name;
			
			internal int mode;
			
			internal gltmode_t(System.String name, int mode)
			{
				this.name = name;
				this.mode = mode;
			}
		}
		
		//UPGRADE_NOTE: Final was removed from the declaration of 'gl_alpha_modes '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'"
		internal static readonly gltmode_t[] gl_alpha_modes = new gltmode_t[]{new gltmode_t("default", 4), new gltmode_t("GL_RGBA", net.java.games.jogl.GL_Fields.GL_RGBA), new gltmode_t("GL_RGBA8", net.java.games.jogl.GL_Fields.GL_RGBA8), new gltmode_t("GL_RGB5_A1", net.java.games.jogl.GL_Fields.GL_RGB5_A1), new gltmode_t("GL_RGBA4", net.java.games.jogl.GL_Fields.GL_RGBA4), new gltmode_t("GL_RGBA2", net.java.games.jogl.GL_Fields.GL_RGBA2)};
		
		//UPGRADE_NOTE: Final was removed from the declaration of 'NUM_GL_ALPHA_MODES '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'"
		internal static readonly int NUM_GL_ALPHA_MODES = gl_alpha_modes.Length;
		
		//UPGRADE_NOTE: Final was removed from the declaration of 'gl_solid_modes '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'"
		internal static readonly gltmode_t[] gl_solid_modes = new gltmode_t[]{new gltmode_t("default", 3), new gltmode_t("GL_RGB", net.java.games.jogl.GL_Fields.GL_RGB), new gltmode_t("GL_RGB8", net.java.games.jogl.GL_Fields.GL_RGB8), new gltmode_t("GL_RGB5", net.java.games.jogl.GL_Fields.GL_RGB5), new gltmode_t("GL_RGB4", net.java.games.jogl.GL_Fields.GL_RGB4), new gltmode_t("GL_R3_G3_B2", net.java.games.jogl.GL_Fields.GL_R3_G3_B2), new gltmode_t("GL_RGB2", net.java.games.jogl.GL_Fields.GL_RGB2_EXT)};
		
		//UPGRADE_NOTE: Final was removed from the declaration of 'NUM_GL_SOLID_MODES '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'"
		internal static readonly int NUM_GL_SOLID_MODES = gl_solid_modes.Length;
		
		/*
		* GL_TextureMode
		*/
		internal override void  GL_TextureMode(System.String string_Renamed)
		{
			
			int i;
			for (i = 0; i < NUM_GL_MODES; i++)
			{
				if (modes[i].name.ToUpper().Equals(string_Renamed.ToUpper()))
					break;
			}
			
			if (i == NUM_GL_MODES)
			{
				VID.Printf(Defines.PRINT_ALL, "bad filter name: [" + string_Renamed + "]\n");
				return ;
			}
			
			gl_filter_min = modes[i].minimize;
			gl_filter_max = modes[i].maximize;
			
			image_t glt;
			// change all the existing mipmap texture objects
			for (i = 0; i < numgltextures; i++)
			{
				glt = gltextures[i];
				
				if (glt.type != it_pic && glt.type != it_sky)
				{
					GL_Bind(glt.texnum);
					gl.glTexParameteri(net.java.games.jogl.GL_Fields.GL_TEXTURE_2D, net.java.games.jogl.GL_Fields.GL_TEXTURE_MIN_FILTER, gl_filter_min);
					gl.glTexParameteri(net.java.games.jogl.GL_Fields.GL_TEXTURE_2D, net.java.games.jogl.GL_Fields.GL_TEXTURE_MAG_FILTER, gl_filter_max);
				}
			}
		}
		
		/*
		* GL_TextureAlphaMode
		*/
		internal override void  GL_TextureAlphaMode(System.String string_Renamed)
		{
			
			int i;
			for (i = 0; i < NUM_GL_ALPHA_MODES; i++)
			{
				if (gl_alpha_modes[i].name.ToUpper().Equals(string_Renamed.ToUpper()))
					break;
			}
			
			if (i == NUM_GL_ALPHA_MODES)
			{
				VID.Printf(Defines.PRINT_ALL, "bad alpha texture mode name: [" + string_Renamed + "]\n");
				return ;
			}
			
			gl_tex_alpha_format = gl_alpha_modes[i].mode;
		}
		
		/*
		* GL_TextureSolidMode
		*/
		internal override void  GL_TextureSolidMode(System.String string_Renamed)
		{
			int i;
			for (i = 0; i < NUM_GL_SOLID_MODES; i++)
			{
				if (gl_solid_modes[i].name.ToUpper().Equals(string_Renamed.ToUpper()))
					break;
			}
			
			if (i == NUM_GL_SOLID_MODES)
			{
				VID.Printf(Defines.PRINT_ALL, "bad solid texture mode name: [" + string_Renamed + "]\n");
				return ;
			}
			
			gl_tex_solid_format = gl_solid_modes[i].mode;
		}
		
		/*
		* GL_ImageList_f
		*/
		internal override void  GL_ImageList_f()
		{
			
			image_t image;
			int texels;
			//UPGRADE_NOTE: Final was removed from the declaration of 'palstrings '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'"
			System.String[] palstrings = new System.String[]{"RGB", "PAL"};
			
			VID.Printf(Defines.PRINT_ALL, "------------------\n");
			texels = 0;
			
			for (int i = 0; i < numgltextures; i++)
			{
				image = gltextures[i];
				if (image.texnum <= 0)
					continue;
				
				texels += image.upload_width * image.upload_height;
				switch (image.type)
				{
					
					case it_skin: 
						VID.Printf(Defines.PRINT_ALL, "M");
						break;
					
					case it_sprite: 
						VID.Printf(Defines.PRINT_ALL, "S");
						break;
					
					case it_wall: 
						VID.Printf(Defines.PRINT_ALL, "W");
						break;
					
					case it_pic: 
						VID.Printf(Defines.PRINT_ALL, "P");
						break;
					
					default: 
						VID.Printf(Defines.PRINT_ALL, " ");
						break;
					
				}
				
				VID.Printf(Defines.PRINT_ALL, " %3i %3i %s: %s\n", new Vargs(4).add(image.upload_width).add(image.upload_height).add(palstrings[(image.paletted)?1:0]).add(image.name));
			}
			VID.Printf(Defines.PRINT_ALL, "Total texel count (not counting mipmaps): " + texels + '\n');
		}
		
		/*
		* ==================================================
		* 
		* scrap allocation
		* 
		* Allocate all the little status bar objects into a single texture to
		* crutch up inefficient hardware / drivers
		* 
		* ==================================================
		*/
		
		internal const int MAX_SCRAPS = 1;
		
		internal const int BLOCK_WIDTH = 256;
		
		internal const int BLOCK_HEIGHT = 256;
		
		internal int[][] scrap_allocated = new int[MAX_SCRAPS][];
		
		internal sbyte[][] scrap_texels = new sbyte[MAX_SCRAPS][];
		
		internal bool scrap_dirty;
		
		internal class pos_t
		{
			internal int x, y;
			
			internal pos_t(int x, int y)
			{
				this.x = x;
				this.y = y;
			}
		}
		
		// returns a texture number and the position inside it
		internal virtual int Scrap_AllocBlock(int w, int h, pos_t pos)
		{
			int i, j;
			int best, best2;
			int texnum;
			
			for (texnum = 0; texnum < MAX_SCRAPS; texnum++)
			{
				best = BLOCK_HEIGHT;
				
				for (i = 0; i < BLOCK_WIDTH - w; i++)
				{
					best2 = 0;
					
					for (j = 0; j < w; j++)
					{
						if (scrap_allocated[texnum][i + j] >= best)
							break;
						if (scrap_allocated[texnum][i + j] > best2)
							best2 = scrap_allocated[texnum][i + j];
					}
					if (j == w)
					{
						// this is a valid spot
						pos.x = i;
						pos.y = best = best2;
					}
				}
				
				if (best + h > BLOCK_HEIGHT)
					continue;
				
				for (i = 0; i < w; i++)
					scrap_allocated[texnum][pos.x + i] = best + h;
				
				return texnum;
			}
			return - 1;
		}
		
		internal int scrap_uploads = 0;
		
		internal virtual void  Scrap_Upload()
		{
			scrap_uploads++;
			GL_Bind(TEXNUM_SCRAPS);
			GL_Upload8(scrap_texels[0], BLOCK_WIDTH, BLOCK_HEIGHT, false, false);
			scrap_dirty = false;
		}
		
		/*
		* ==================================================
		* 
		* PCX LOADING
		* 
		* ==================================================
		*/
		
		private static sbyte[] tmpImage8 = new sbyte[512 * 512 * 4];
		
		private static int[] tmpImage32 = new int[512 * 512];
		
		/*
		* LoadPCX
		*/
		//UPGRADE_NOTE: ref keyword was added to struct-type parameters. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1303'"
		internal virtual int LoadPCX(System.String filename, sbyte[][] palette, ref System.Drawing.Size dim)
		{
			qfiles.pcx_t pcx;
			
			// load the file
			ByteBuffer raw = FS.LoadMappedFile(filename);
			
			if (raw == null)
			{
				VID.Printf(Defines.PRINT_DEVELOPER, "Bad pcx file " + filename + '\n');
				return 0;
			}
			
			// parse the PCX file
			pcx = new qfiles.pcx_t(raw);
			
			if (pcx.manufacturer != 0x0a || pcx.version != 5 || pcx.encoding != 1 || pcx.bits_per_pixel != 8 || pcx.xmax >= 640 || pcx.ymax >= 480)
			{
				
				VID.Printf(Defines.PRINT_ALL, "Bad pcx file " + filename + '\n');
				return 0;
			}
			
			int width = pcx.xmax - pcx.xmin + 1;
			int height = pcx.ymax - pcx.ymin + 1;
			
			sbyte[] pix = tmpImage8;
			
			if (palette != null)
			{
				palette[0] = new sbyte[768];
				raw.position(raw.limit() - 768);
				raw.get_Renamed(palette[0]);
			}
			
			if (!dim.IsEmpty)
			{
				dim.Width = width;
				dim.Height = height;
			}
			
			//
			// decode pcx
			//
			int count = 0;
			sbyte dataByte = 0;
			int runLength = 0;
			int x, y;
			
			// simple counter for buffer indexing
			int p = 0;
			
			for (y = 0; y < height; y++)
			{
				for (x = 0; x < width; )
				{
					
					dataByte = pcx.data.get_Renamed(p++);
					
					if ((dataByte & 0xC0) == 0xC0)
					{
						runLength = dataByte & 0x3F;
						dataByte = pcx.data.get_Renamed(p++);
						// write runLength pixel
						while (runLength-- > 0)
						{
							pix[count++] = dataByte;
							x++;
						}
					}
					else
					{
						// write one pixel
						pix[count++] = dataByte;
						x++;
					}
				}
			}
			return width * height;
		}
		
		/*
		* ==================================================
		* 
		* TARGA LOADING
		* 
		* ==================================================
		*/
		
		/*
		* LoadTGA
		*/
		//UPGRADE_NOTE: ref keyword was added to struct-type parameters. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1303'"
		internal virtual int LoadTGA(System.String name, ref System.Drawing.Size dim)
		{
			int columns, rows, numPixels;
			int pixbuf; // index into pic
			int row, column;
			ByteBuffer buf_p;
			int length;
			qfiles.tga_t targa_header;
			sbyte[] pic = null;
			
			//
			// load the file
			//
			ByteBuffer raw = FS.LoadMappedFile(name);
			
			if (raw == null)
			{
				VID.Printf(Defines.PRINT_DEVELOPER, "Bad tga file " + name + '\n');
				return 0;
			}
			
			targa_header = new qfiles.tga_t(raw);
			
			if (targa_header.image_type != 2 && targa_header.image_type != 10)
				Com.Error(Defines.ERR_DROP, "LoadTGA: Only type 2 and 10 targa RGB images supported\n");
			
			if (targa_header.colormap_type != 0 || (targa_header.pixel_size != 32 && targa_header.pixel_size != 24))
				Com.Error(Defines.ERR_DROP, "LoadTGA: Only 32 or 24 bit images supported (no colormaps)\n");
			
			columns = targa_header.width;
			rows = targa_header.height;
			numPixels = columns * rows;
			
			if (!dim.IsEmpty)
			{
				dim.Width = columns;
				dim.Height = rows;
			}
			
			// targa_rgba;
			pic = tmpImage8;
			
			// skip TARGA image comment
			if (targa_header.id_length != 0)
				targa_header.data.position(targa_header.id_length);
			
			buf_p = targa_header.data;
			
			sbyte red, green, blue, alphabyte;
			red = green = blue = alphabyte = 0;
			int packetHeader, packetSize, j;
			
			if (targa_header.image_type == 2)
			{
				// Uncompressed,
				// RGB images
				for (row = rows - 1; row >= 0; row--)
				{
					
					pixbuf = row * columns * 4;
					
					for (column = 0; column < columns; column++)
					{
						switch (targa_header.pixel_size)
						{
							
							case 24: 
								
								blue = buf_p.get_Renamed();
								green = buf_p.get_Renamed();
								red = buf_p.get_Renamed();
								pic[pixbuf++] = red;
								pic[pixbuf++] = green;
								pic[pixbuf++] = blue;
								pic[pixbuf++] = (sbyte) SupportClass.Identity(255);
								break;
							
							case 32: 
								blue = buf_p.get_Renamed();
								green = buf_p.get_Renamed();
								red = buf_p.get_Renamed();
								alphabyte = buf_p.get_Renamed();
								pic[pixbuf++] = red;
								pic[pixbuf++] = green;
								pic[pixbuf++] = blue;
								pic[pixbuf++] = alphabyte;
								break;
							}
					}
				}
			}
			else if (targa_header.image_type == 10)
			{
				// Runlength
				// encoded
				// RGB
				// images
				for (row = rows - 1; row >= 0; row--)
				{
					
					pixbuf = row * columns * 4;
					try
					{
						
						for (column = 0; column < columns; )
						{
							
							packetHeader = buf_p.get_Renamed() & 0xFF;
							packetSize = 1 + (packetHeader & 0x7f);
							
							if ((packetHeader & 0x80) != 0)
							{
								// run-length
								// packet
								switch (targa_header.pixel_size)
								{
									
									case 24: 
										blue = buf_p.get_Renamed();
										green = buf_p.get_Renamed();
										red = buf_p.get_Renamed();
										alphabyte = (sbyte) SupportClass.Identity(255);
										break;
									
									case 32: 
										blue = buf_p.get_Renamed();
										green = buf_p.get_Renamed();
										red = buf_p.get_Renamed();
										alphabyte = buf_p.get_Renamed();
										break;
									}
								
								for (j = 0; j < packetSize; j++)
								{
									pic[pixbuf++] = red;
									pic[pixbuf++] = green;
									pic[pixbuf++] = blue;
									pic[pixbuf++] = alphabyte;
									column++;
									// run spans across rows
									if (column == columns)
									{
										column = 0;
										if (row > 0)
											row--;
										// goto label breakOut;
										else
											throw new longjmpException();
										
										pixbuf = row * columns * 4;
									}
								}
							}
							else
							{
								// non run-length packet
								for (j = 0; j < packetSize; j++)
								{
									switch (targa_header.pixel_size)
									{
										
										case 24: 
											blue = buf_p.get_Renamed();
											green = buf_p.get_Renamed();
											red = buf_p.get_Renamed();
											pic[pixbuf++] = red;
											pic[pixbuf++] = green;
											pic[pixbuf++] = blue;
											pic[pixbuf++] = (sbyte) SupportClass.Identity(255);
											break;
										
										case 32: 
											blue = buf_p.get_Renamed();
											green = buf_p.get_Renamed();
											red = buf_p.get_Renamed();
											alphabyte = buf_p.get_Renamed();
											pic[pixbuf++] = red;
											pic[pixbuf++] = green;
											pic[pixbuf++] = blue;
											pic[pixbuf++] = alphabyte;
											break;
										}
									column++;
									// pixel packet run spans across rows
									if (column == columns)
									{
										column = 0;
										if (row > 0)
											row--;
										// goto label breakOut;
										else
											throw new longjmpException();
										
										pixbuf = row * columns * 4;
									}
								}
							}
						}
					}
					catch (longjmpException e)
					{
						// label breakOut:
					}
				}
			}
			return numPixels * 4;
		}
		
		/*
		* ==================================================
		* 
		* IMAGE FLOOD FILLING
		* 
		* ==================================================
		*/
		
		/*
		* Mod_FloodFillSkin
		* 
		* Fill background pixels so mipmapping doesn't have haloes
		*/
		
		internal class floodfill_t
		{
			internal short x, y;
		}
		
		// must be a power of 2
		internal const int FLOODFILL_FIFO_SIZE = 0x1000;
		
		//UPGRADE_NOTE: Final was removed from the declaration of 'FLOODFILL_FIFO_MASK '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'"
		internal static readonly int FLOODFILL_FIFO_MASK = FLOODFILL_FIFO_SIZE - 1;
		
		internal static floodfill_t[] fifo = new floodfill_t[FLOODFILL_FIFO_SIZE];
		
		// TODO check this: R_FloodFillSkin( byte[] skin, int skinwidth, int
		// skinheight)
		internal virtual void  R_FloodFillSkin(sbyte[] skin, int skinwidth, int skinheight)
		{
			// assume this is the pixel to fill
			int fillcolor = skin[0] & 0xFF;
			//		floodfill_t[] fifo = new floodfill_t[FLOODFILL_FIFO_SIZE];
			int inpt = 0, outpt = 0;
			int filledcolor = - 1;
			int i;
			
			//		for (int j = 0; j < fifo.length; j++) {
			//			fifo[j] = new floodfill_t();
			//		}
			
			if (filledcolor == - 1)
			{
				filledcolor = 0;
				// attempt to find opaque black
				for (i = 0; i < 256; ++i)
					if (d_8to24table[i] == 0xFF000000)
					{
						// alpha
						// 1.0
						filledcolor = i;
						break;
					}
			}
			
			// can't fill to filled color or to transparent color (used as visited
			// marker)
			if ((fillcolor == filledcolor) || (fillcolor == 255))
			{
				return ;
			}
			
			fifo[inpt].x = 0;
			fifo[inpt].y = 0;
			inpt = (inpt + 1) & FLOODFILL_FIFO_MASK;
			
			while (outpt != inpt)
			{
				int x = fifo[outpt].x;
				int y = fifo[outpt].y;
				int fdc = filledcolor;
				int pos = x + skinwidth * y;
				//
				outpt = (outpt + 1) & FLOODFILL_FIFO_MASK;
				
				int off, dx, dy;
				
				if (x > 0)
				{
					// FLOODFILL_STEP( -1, -1, 0 );
					off = - 1;
					dx = - 1;
					dy = 0;
					if (skin[pos + off] == (sbyte) fillcolor)
					{
						skin[pos + off] = (sbyte) SupportClass.Identity(255);
						fifo[inpt].x = (short) (x + dx);
						fifo[inpt].y = (short) (y + dy);
						inpt = (inpt + 1) & FLOODFILL_FIFO_MASK;
					}
					else if (skin[pos + off] != (sbyte) SupportClass.Identity(255))
						fdc = skin[pos + off] & 0xff;
				}
				
				if (x < skinwidth - 1)
				{
					// FLOODFILL_STEP( 1, 1, 0 );
					off = 1;
					dx = 1;
					dy = 0;
					if (skin[pos + off] == (sbyte) fillcolor)
					{
						skin[pos + off] = (sbyte) SupportClass.Identity(255);
						fifo[inpt].x = (short) (x + dx);
						fifo[inpt].y = (short) (y + dy);
						inpt = (inpt + 1) & FLOODFILL_FIFO_MASK;
					}
					else if (skin[pos + off] != (sbyte) SupportClass.Identity(255))
						fdc = skin[pos + off] & 0xff;
				}
				
				if (y > 0)
				{
					// FLOODFILL_STEP( -skinwidth, 0, -1 );
					off = - skinwidth;
					dx = 0;
					dy = - 1;
					if (skin[pos + off] == (sbyte) fillcolor)
					{
						skin[pos + off] = (sbyte) SupportClass.Identity(255);
						fifo[inpt].x = (short) (x + dx);
						fifo[inpt].y = (short) (y + dy);
						inpt = (inpt + 1) & FLOODFILL_FIFO_MASK;
					}
					else if (skin[pos + off] != (sbyte) SupportClass.Identity(255))
						fdc = skin[pos + off] & 0xff;
				}
				
				if (y < skinheight - 1)
				{
					// FLOODFILL_STEP( skinwidth, 0, 1 );
					off = skinwidth;
					dx = 0;
					dy = 1;
					if (skin[pos + off] == (sbyte) fillcolor)
					{
						skin[pos + off] = (sbyte) SupportClass.Identity(255);
						fifo[inpt].x = (short) (x + dx);
						fifo[inpt].y = (short) (y + dy);
						inpt = (inpt + 1) & FLOODFILL_FIFO_MASK;
					}
					else if (skin[pos + off] != (sbyte) SupportClass.Identity(255))
						fdc = skin[pos + off] & 0xff;
				}
				
				skin[x + skinwidth * y] = (sbyte) fdc;
			}
		}
		
		// ==================================================
		
		internal int[] p1 = new int[1024];
		
		internal int[] p2 = new int[1024];
		
		/*
		* GL_ResampleTexture
		*/
		internal virtual void  GL_ResampleTexture(int[] in_Renamed, int inwidth, int inheight, int[] out_Renamed, int outwidth, int outheight)
		{
			
			SupportClass.ArraySupport.Fill(p1, 0);
			SupportClass.ArraySupport.Fill(p2, 0);
			
			int fracstep = (inwidth * 0x10000) / outwidth;
			
			int i, j;
			int frac = fracstep >> 2;
			for (i = 0; i < outwidth; i++)
			{
				p1[i] = frac >> 16;
				frac += fracstep;
			}
			frac = 3 * (fracstep >> 2);
			for (i = 0; i < outwidth; i++)
			{
				p2[i] = frac >> 16;
				frac += fracstep;
			}
			
			int outp = 0;
			int r, g, b, a;
			int inrow, inrow2;
			int pix1, pix2, pix3, pix4;
			
			for (i = 0; i < outheight; i++)
			{
				//UPGRADE_WARNING: Data types in Visual C# might be different.  Verify the accuracy of narrowing conversions. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1042'"
				inrow = inwidth * (int) ((i + 0.25f) * inheight / outheight);
				//UPGRADE_WARNING: Data types in Visual C# might be different.  Verify the accuracy of narrowing conversions. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1042'"
				inrow2 = inwidth * (int) ((i + 0.75f) * inheight / outheight);
				frac = fracstep >> 1;
				for (j = 0; j < outwidth; j++)
				{
					pix1 = in_Renamed[inrow + p1[j]];
					pix2 = in_Renamed[inrow + p2[j]];
					pix3 = in_Renamed[inrow2 + p1[j]];
					pix4 = in_Renamed[inrow2 + p2[j]];
					
					r = (((pix1 >> 0) & 0xFF) + ((pix2 >> 0) & 0xFF) + ((pix3 >> 0) & 0xFF) + ((pix4 >> 0) & 0xFF)) >> 2;
					g = (((pix1 >> 8) & 0xFF) + ((pix2 >> 8) & 0xFF) + ((pix3 >> 8) & 0xFF) + ((pix4 >> 8) & 0xFF)) >> 2;
					b = (((pix1 >> 16) & 0xFF) + ((pix2 >> 16) & 0xFF) + ((pix3 >> 16) & 0xFF) + ((pix4 >> 16) & 0xFF)) >> 2;
					a = (((pix1 >> 24) & 0xFF) + ((pix2 >> 24) & 0xFF) + ((pix3 >> 24) & 0xFF) + ((pix4 >> 24) & 0xFF)) >> 2;
					
					out_Renamed[outp++] = (a << 24) | (b << 16) | (g << 8) | r;
				}
			}
		}
		
		/*
		* GL_LightScaleTexture
		* 
		* Scale up the pixel values in a texture to increase the lighting range
		*/
		internal virtual void  GL_LightScaleTexture(int[] in_Renamed, int inwidth, int inheight, bool only_gamma)
		{
			if (only_gamma)
			{
				int i, c;
				int r, g, b, color;
				
				c = inwidth * inheight;
				for (i = 0; i < c; i++)
				{
					color = in_Renamed[i];
					r = (color >> 0) & 0xFF;
					g = (color >> 8) & 0xFF;
					b = (color >> 16) & 0xFF;
					
					r = gammatable[r] & 0xFF;
					g = gammatable[g] & 0xFF;
					b = gammatable[b] & 0xFF;
					
					in_Renamed[i] = (r << 0) | (g << 8) | (b << 16) | (color & unchecked((int) 0xFF000000));
				}
			}
			else
			{
				int i, c;
				int r, g, b, color;
				
				c = inwidth * inheight;
				for (i = 0; i < c; i++)
				{
					color = in_Renamed[i];
					r = (color >> 0) & 0xFF;
					g = (color >> 8) & 0xFF;
					b = (color >> 16) & 0xFF;
					
					r = gammatable[intensitytable[r] & 0xFF] & 0xFF;
					g = gammatable[intensitytable[g] & 0xFF] & 0xFF;
					b = gammatable[intensitytable[b] & 0xFF] & 0xFF;
					
					in_Renamed[i] = (r << 0) | (g << 8) | (b << 16) | (color & unchecked((int) 0xFF000000));
				}
			}
		}
		
		/*
		* GL_MipMap
		* 
		* Operates in place, quartering the size of the texture
		*/
		internal virtual void  GL_MipMap(int[] in_Renamed, int width, int height)
		{
			int i, j;
			int[] out_Renamed;
			
			out_Renamed = in_Renamed;
			
			int inIndex = 0;
			int outIndex = 0;
			
			int r, g, b, a;
			int p1, p2, p3, p4;
			
			for (i = 0; i < height; i += 2, inIndex += width)
			{
				for (j = 0; j < width; j += 2, outIndex += 1, inIndex += 2)
				{
					
					p1 = in_Renamed[inIndex + 0];
					p2 = in_Renamed[inIndex + 1];
					p3 = in_Renamed[inIndex + width + 0];
					p4 = in_Renamed[inIndex + width + 1];
					
					r = (((p1 >> 0) & 0xFF) + ((p2 >> 0) & 0xFF) + ((p3 >> 0) & 0xFF) + ((p4 >> 0) & 0xFF)) >> 2;
					g = (((p1 >> 8) & 0xFF) + ((p2 >> 8) & 0xFF) + ((p3 >> 8) & 0xFF) + ((p4 >> 8) & 0xFF)) >> 2;
					b = (((p1 >> 16) & 0xFF) + ((p2 >> 16) & 0xFF) + ((p3 >> 16) & 0xFF) + ((p4 >> 16) & 0xFF)) >> 2;
					a = (((p1 >> 24) & 0xFF) + ((p2 >> 24) & 0xFF) + ((p3 >> 24) & 0xFF) + ((p4 >> 24) & 0xFF)) >> 2;
					
					out_Renamed[outIndex] = (r << 0) | (g << 8) | (b << 16) | (a << 24);
				}
			}
		}
		
		/*
		* GL_Upload32
		* 
		* Returns has_alpha
		*/
		internal virtual void  GL_BuildPalettedTexture(sbyte[] paletted_texture, int[] scaled, int scaled_width, int scaled_height)
		{
			
			int r, g, b, c;
			int size = scaled_width * scaled_height;
			
			for (int i = 0; i < size; i++)
			{
				
				r = (scaled[i] >> 3) & 31;
				g = (scaled[i] >> 10) & 63;
				b = (scaled[i] >> 19) & 31;
				
				c = r | (g << 5) | (b << 11);
				
				paletted_texture[i] = gl_state.d_16to8table[c];
			}
		}
		
		internal int upload_width, upload_height;
		
		internal bool uploaded_paletted;
		
		internal int[] scaled = new int[256 * 256];
		
		internal sbyte[] paletted_texture = new sbyte[256 * 256];
		
		//UPGRADE_NOTE: The initialization of  'tex' was moved to method 'InitBlock'. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1005'"
		internal IntBuffer tex;
		
		/*
		* GL_Upload32
		* 
		* Returns has_alpha
		*/
		internal virtual bool GL_Upload32(int[] data, int width, int height, bool mipmap)
		{
			int samples;
			int scaled_width, scaled_height;
			int i, c;
			int comp;
			
			SupportClass.ArraySupport.Fill(scaled, 0);
			SupportClass.ArraySupport.Fill(SupportClass.ToByteArray(paletted_texture), (byte) 0);
			
			uploaded_paletted = false;
			
			for (scaled_width = 1; scaled_width < width; scaled_width <<= 1)
				;
			if (gl_round_down.value_Renamed > 0.0f && scaled_width > width && mipmap)
				scaled_width >>= 1;
			for (scaled_height = 1; scaled_height < height; scaled_height <<= 1)
				;
			if (gl_round_down.value_Renamed > 0.0f && scaled_height > height && mipmap)
				scaled_height >>= 1;
			
			// let people sample down the world textures for speed
			if (mipmap)
			{
				//UPGRADE_WARNING: Data types in Visual C# might be different.  Verify the accuracy of narrowing conversions. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1042'"
				scaled_width >>= (int) gl_picmip.value_Renamed;
				//UPGRADE_WARNING: Data types in Visual C# might be different.  Verify the accuracy of narrowing conversions. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1042'"
				scaled_height >>= (int) gl_picmip.value_Renamed;
			}
			
			// don't ever bother with >256 textures
			if (scaled_width > 256)
				scaled_width = 256;
			if (scaled_height > 256)
				scaled_height = 256;
			
			if (scaled_width < 1)
				scaled_width = 1;
			if (scaled_height < 1)
				scaled_height = 1;
			
			upload_width = scaled_width;
			upload_height = scaled_height;
			
			if (scaled_width * scaled_height > 256 * 256)
				Com.Error(Defines.ERR_DROP, "GL_Upload32: too big");
			
			// scan the texture for any non-255 alpha
			c = width * height;
			samples = gl_solid_format;
			
			for (i = 0; i < c; i++)
			{
				if ((data[i] & unchecked((int) 0xff000000)) != 0xff000000)
				{
					samples = gl_alpha_format;
					break;
				}
			}
			
			if (samples == gl_solid_format)
				comp = gl_tex_solid_format;
			else if (samples == gl_alpha_format)
				comp = gl_tex_alpha_format;
			else
			{
				VID.Printf(Defines.PRINT_ALL, "Unknown number of texture components " + samples + '\n');
				comp = samples;
			}
			
			// simulates a goto
			try
			{
				if (scaled_width == width && scaled_height == height)
				{
					if (!mipmap)
					{
						if (qglColorTableEXT && gl_ext_palettedtexture.value_Renamed != 0.0f && samples == gl_solid_format)
						{
							uploaded_paletted = true;
							GL_BuildPalettedTexture(paletted_texture, data, scaled_width, scaled_height);
							gl.glTexImage2D(net.java.games.jogl.GL_Fields.GL_TEXTURE_2D, 0, GL_COLOR_INDEX8_EXT, scaled_width, scaled_height, 0, net.java.games.jogl.GL_Fields.GL_COLOR_INDEX, net.java.games.jogl.GL_Fields.GL_UNSIGNED_BYTE, paletted_texture);
						}
						else
						{
							tex.rewind();
							tex.put(data, 0, scaled_width * scaled_height);
							gl.glTexImage2D(net.java.games.jogl.GL_Fields.GL_TEXTURE_2D, 0, comp, scaled_width, scaled_height, 0, net.java.games.jogl.GL_Fields.GL_RGBA, net.java.games.jogl.GL_Fields.GL_UNSIGNED_BYTE, tex);
						}
						//goto done;
						throw new longjmpException();
					}
					Array.Copy(data, 0, scaled, 0, scaled_width * scaled_height);
				}
				else
					GL_ResampleTexture(data, width, height, scaled, scaled_width, scaled_height);
				
				GL_LightScaleTexture(scaled, scaled_width, scaled_height, !mipmap);
				
				if (qglColorTableEXT && gl_ext_palettedtexture.value_Renamed != 0.0f && (samples == gl_solid_format))
				{
					uploaded_paletted = true;
					GL_BuildPalettedTexture(paletted_texture, scaled, scaled_width, scaled_height);
					gl.glTexImage2D(net.java.games.jogl.GL_Fields.GL_TEXTURE_2D, 0, GL_COLOR_INDEX8_EXT, scaled_width, scaled_height, 0, net.java.games.jogl.GL_Fields.GL_COLOR_INDEX, net.java.games.jogl.GL_Fields.GL_UNSIGNED_BYTE, paletted_texture);
				}
				else
				{
					tex.rewind();
					tex.put(scaled, 0, scaled_width * scaled_height);
					gl.glTexImage2D(net.java.games.jogl.GL_Fields.GL_TEXTURE_2D, 0, comp, scaled_width, scaled_height, 0, net.java.games.jogl.GL_Fields.GL_RGBA, net.java.games.jogl.GL_Fields.GL_UNSIGNED_BYTE, tex);
				}
				
				if (mipmap)
				{
					int miplevel;
					miplevel = 0;
					while (scaled_width > 1 || scaled_height > 1)
					{
						GL_MipMap(scaled, scaled_width, scaled_height);
						scaled_width >>= 1;
						scaled_height >>= 1;
						if (scaled_width < 1)
							scaled_width = 1;
						if (scaled_height < 1)
							scaled_height = 1;
						
						miplevel++;
						if (qglColorTableEXT && gl_ext_palettedtexture.value_Renamed != 0.0f && samples == gl_solid_format)
						{
							uploaded_paletted = true;
							GL_BuildPalettedTexture(paletted_texture, scaled, scaled_width, scaled_height);
							gl.glTexImage2D(net.java.games.jogl.GL_Fields.GL_TEXTURE_2D, miplevel, GL_COLOR_INDEX8_EXT, scaled_width, scaled_height, 0, net.java.games.jogl.GL_Fields.GL_COLOR_INDEX, net.java.games.jogl.GL_Fields.GL_UNSIGNED_BYTE, paletted_texture);
						}
						else
						{
							tex.rewind();
							tex.put(scaled, 0, scaled_width * scaled_height);
							gl.glTexImage2D(net.java.games.jogl.GL_Fields.GL_TEXTURE_2D, miplevel, comp, scaled_width, scaled_height, 0, net.java.games.jogl.GL_Fields.GL_RGBA, net.java.games.jogl.GL_Fields.GL_UNSIGNED_BYTE, tex);
						}
					}
				}
				// label done:
			}
			catch (longjmpException e)
			{
				// replaces label done
			}
			
			if (mipmap)
			{
				gl.glTexParameterf(net.java.games.jogl.GL_Fields.GL_TEXTURE_2D, net.java.games.jogl.GL_Fields.GL_TEXTURE_MIN_FILTER, gl_filter_min);
				gl.glTexParameterf(net.java.games.jogl.GL_Fields.GL_TEXTURE_2D, net.java.games.jogl.GL_Fields.GL_TEXTURE_MAG_FILTER, gl_filter_max);
			}
			else
			{
				gl.glTexParameterf(net.java.games.jogl.GL_Fields.GL_TEXTURE_2D, net.java.games.jogl.GL_Fields.GL_TEXTURE_MIN_FILTER, gl_filter_max);
				gl.glTexParameterf(net.java.games.jogl.GL_Fields.GL_TEXTURE_2D, net.java.games.jogl.GL_Fields.GL_TEXTURE_MAG_FILTER, gl_filter_max);
			}
			
			return (samples == gl_alpha_format);
		}
		
		internal int[] trans = new int[512 * 256];
		
		/*
		* GL_Upload8
		* 
		* Returns has_alpha
		*/
		internal virtual bool GL_Upload8(sbyte[] data, int width, int height, bool mipmap, bool is_sky)
		{
			
			SupportClass.ArraySupport.Fill(trans, 0);
			
			int s = width * height;
			
			if (s > trans.Length)
				Com.Error(Defines.ERR_DROP, "GL_Upload8: too large");
			
			if (qglColorTableEXT && gl_ext_palettedtexture.value_Renamed != 0.0f && is_sky)
			{
				gl.glTexImage2D(net.java.games.jogl.GL_Fields.GL_TEXTURE_2D, 0, GL_COLOR_INDEX8_EXT, width, height, 0, net.java.games.jogl.GL_Fields.GL_COLOR_INDEX, net.java.games.jogl.GL_Fields.GL_UNSIGNED_BYTE, data);
				
				gl.glTexParameterf(net.java.games.jogl.GL_Fields.GL_TEXTURE_2D, net.java.games.jogl.GL_Fields.GL_TEXTURE_MIN_FILTER, gl_filter_max);
				gl.glTexParameterf(net.java.games.jogl.GL_Fields.GL_TEXTURE_2D, net.java.games.jogl.GL_Fields.GL_TEXTURE_MAG_FILTER, gl_filter_max);
				
				return false;
			}
			else
			{
				int p;
				int rgb;
				for (int i = 0; i < s; i++)
				{
					p = data[i] & 0xff;
					trans[i] = d_8to24table[p];
					
					if (p == 255)
					{
						// transparent, so scan around for another
						// color
						// to avoid alpha fringes
						// FIXME: do a full flood fill so mips work...
						if (i > width && (data[i - width] & 0xff) != 255)
							p = data[i - width] & 0xff;
						else if (i < s - width && (data[i + width] & 0xff) != 255)
							p = data[i + width] & 0xff;
						else if (i > 0 && (data[i - 1] & 0xff) != 255)
							p = data[i - 1] & 0xff;
						else if (i < s - 1 && (data[i + 1] & 0xff) != 255)
							p = data[i + 1] & 0xff;
						else
							p = 0;
						// copy rgb components
						trans[i] = d_8to24table[p] & 0x00FFFFFF; // only
						// rgb
					}
				}
				
				return GL_Upload32(trans, width, height, mipmap);
			}
		}
		
		/*
		* GL_LoadPic
		* 
		* This is also used as an entry point for the generated r_notexture
		*/
		internal virtual image_t GL_LoadPic(System.String name, sbyte[] pic, int width, int height, int type, int bits)
		{
			image_t image;
			int i;
			
			// find a free image_t
			for (i = 0; i < numgltextures; i++)
			{
				image = gltextures[i];
				if (image.texnum == 0)
					break;
			}
			
			if (i == numgltextures)
			{
				if (numgltextures == MAX_GLTEXTURES)
					Com.Error(Defines.ERR_DROP, "MAX_GLTEXTURES");
				
				numgltextures++;
			}
			image = gltextures[i];
			
			if (name.Length > Defines.MAX_QPATH)
				Com.Error(Defines.ERR_DROP, "Draw_LoadPic: \"" + name + "\" is too long");
			
			image.name = name;
			image.registration_sequence = registration_sequence;
			
			image.width = width;
			image.height = height;
			image.type = type;
			
			if (type == it_skin && bits == 8)
				R_FloodFillSkin(pic, width, height);
			
			// load little pics into the scrap
			if (image.type == it_pic && bits == 8 && image.width < 64 && image.height < 64)
			{
				pos_t pos = new pos_t(0, 0);
				int j, k;
				
				int texnum = Scrap_AllocBlock(image.width, image.height, pos);
				
				if (texnum == - 1)
				{
					// replace goto nonscrap
					image.scrap = false;
					// image pos in array
					image.texnum = TEXNUM_IMAGES + image.Id;
					GL_Bind(image.texnum);
					
					if (bits == 8)
					{
						image.has_alpha = GL_Upload8(pic, width, height, (image.type != it_pic && image.type != it_sky), image.type == it_sky);
					}
					else
					{
						int[] tmp = tmpImage32;
						int size = width * height;
						
						for (i = 0; i < size; i++)
						{
							tmp[i] = ((pic[4 * i + 0] & 0xFF) << 0);
							tmp[i] |= ((pic[4 * i + 1] & 0xFF) << 8);
							tmp[i] |= ((pic[4 * i + 2] & 0xFF) << 16);
							tmp[i] |= ((pic[4 * i + 3] & 0xFF) << 24);
						}
						
						image.has_alpha = GL_Upload32(tmp, width, height, (image.type != it_pic && image.type != it_sky));
					}
					
					// after power of 2 and scales
					image.upload_width = upload_width;
					image.upload_height = upload_height;
					image.paletted = uploaded_paletted;
					image.sl = 0;
					image.sh = 1;
					image.tl = 0;
					image.th = 1;
					
					return image;
				}
				
				scrap_dirty = true;
				
				// copy the texels into the scrap block
				k = 0;
				for (i = 0; i < image.height; i++)
					for (j = 0; j < image.width; j++, k++)
						scrap_texels[texnum][(pos.y + i) * BLOCK_WIDTH + pos.x + j] = pic[k];
				
				image.texnum = TEXNUM_SCRAPS + texnum;
				image.scrap = true;
				image.has_alpha = true;
				//UPGRADE_WARNING: Data types in Visual C# might be different.  Verify the accuracy of narrowing conversions. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1042'"
				image.sl = (pos.x + 0.01f) / (float) BLOCK_WIDTH;
				//UPGRADE_WARNING: Data types in Visual C# might be different.  Verify the accuracy of narrowing conversions. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1042'"
				image.sh = (pos.x + image.width - 0.01f) / (float) BLOCK_WIDTH;
				//UPGRADE_WARNING: Data types in Visual C# might be different.  Verify the accuracy of narrowing conversions. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1042'"
				image.tl = (pos.y + 0.01f) / (float) BLOCK_WIDTH;
				//UPGRADE_WARNING: Data types in Visual C# might be different.  Verify the accuracy of narrowing conversions. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1042'"
				image.th = (pos.y + image.height - 0.01f) / (float) BLOCK_WIDTH;
			}
			else
			{
				// this was label nonscrap
				
				image.scrap = false;
				
				image.texnum = TEXNUM_IMAGES + image.Id; //image
				// pos
				// in
				// array
				GL_Bind(image.texnum);
				
				if (bits == 8)
				{
					image.has_alpha = GL_Upload8(pic, width, height, (image.type != it_pic && image.type != it_sky), image.type == it_sky);
				}
				else
				{
					int[] tmp = tmpImage32;
					int size = width * height;
					
					for (i = 0; i < size; i++)
					{
						tmp[i] = ((pic[4 * i + 0] & 0xFF) << 0);
						tmp[i] |= ((pic[4 * i + 1] & 0xFF) << 8);
						tmp[i] |= ((pic[4 * i + 2] & 0xFF) << 16);
						tmp[i] |= ((pic[4 * i + 3] & 0xFF) << 24);
					}
					
					image.has_alpha = GL_Upload32(tmp, width, height, (image.type != it_pic && image.type != it_sky));
				}
				// after power of 2 and scales
				image.upload_width = upload_width;
				image.upload_height = upload_height;
				image.paletted = uploaded_paletted;
				image.sl = 0;
				image.sh = 1;
				image.tl = 0;
				image.th = 1;
			}
			return image;
		}
		
		/*
		* GL_LoadWal
		*/
		internal virtual image_t GL_LoadWal(System.String name)
		{
			
			image_t image = null;
			
			ByteBuffer raw = FS.LoadMappedFile(name);
			if (raw == null)
			{
				VID.Printf(Defines.PRINT_ALL, "GL_FindImage: can't load " + name + '\n');
				return r_notexture;
			}
			
			qfiles.miptex_t mt = new qfiles.miptex_t(raw);
			
			sbyte[] pix = tmpImage8;
			raw.position(mt.offsets[0]);
			raw.get_Renamed(pix, 0, mt.width * mt.height);
			image = GL_LoadPic(name, pix, mt.width, mt.height, it_wall, 8);
			
			return image;
		}
		
		/*
		* GL_FindImage
		* 
		* Finds or loads the given image
		*/
		internal virtual image_t GL_FindImage(System.String name, int type)
		{
			image_t image = null;
			
			if (name == null || name.Length < 5)
				return null;
			
			// look for it
			for (int i = 0; i < numgltextures; i++)
			{
				image = gltextures[i];
				if (name.Equals(image.name))
				{
					image.registration_sequence = registration_sequence;
					return image;
				}
			}
			
			//
			// load the pic from disk
			//
			image = null;
			int size = 0;
			System.Drawing.Size dim = new System.Drawing.Size(0, 0);
			
			if (name.EndsWith(".pcx"))
			{
				
				//UPGRADE_NOTE: ref keyword was added to struct-type parameters. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1303'"
				size = LoadPCX(name, null, ref dim);
				if (size == 0)
					return null;
				image = GL_LoadPic(name, tmpImage8, dim.Width, dim.Height, type, 8);
			}
			else if (name.EndsWith(".wal"))
			{
				
				image = GL_LoadWal(name);
			}
			else if (name.EndsWith(".tga"))
			{
				
				//UPGRADE_NOTE: ref keyword was added to struct-type parameters. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1303'"
				size = LoadTGA(name, ref dim);
				
				if (size == 0)
					return null;
				
				image = GL_LoadPic(name, tmpImage8, dim.Width, dim.Height, type, 32);
			}
			
			return image;
		}
		
		/*
		* R_RegisterSkin
		*/
		protected internal virtual image_t R_RegisterSkin(System.String name)
		{
			return GL_FindImage(name, it_skin);
		}
		
		/*
		* GL_FreeUnusedImages
		* 
		* Any image that was not touched on this registration sequence will be
		* freed.
		*/
		internal virtual void  GL_FreeUnusedImages()
		{
			// never free r_notexture or particle texture
			r_notexture.registration_sequence = registration_sequence;
			r_particletexture.registration_sequence = registration_sequence;
			
			image_t image = null;
			
			for (int i = 0; i < numgltextures; i++)
			{
				image = gltextures[i];
				// used this sequence
				if (image.registration_sequence == registration_sequence)
					continue;
				// free image_t slot
				if (image.registration_sequence == 0)
					continue;
				// don't free pics
				if (image.type == it_pic)
					continue;
				
				// free it
				gl.glDeleteTextures(1, new int[]{image.texnum});
				image.clear();
			}
		}
		
		/*
		* Draw_GetPalette
		*/
		protected internal override void  Draw_GetPalette()
		{
			System.Drawing.Size dim;
			// replaces an array pointer (byte[768])
			sbyte[][] palette = new sbyte[1][];
			
			// get the palette
			dim = new System.Drawing.Size(0, 0);
			//UPGRADE_NOTE: ref keyword was added to struct-type parameters. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1303'"
			int size = LoadPCX("pics/colormap.pcx", palette, ref dim);
			
			if (palette[0] == null || palette[0].Length != 768)
				Com.Error(Defines.ERR_FATAL, "Couldn't load pics/colormap.pcx");
			
			sbyte[] pal = palette[0];
			
			int j = 0;
			int r, g, b;
			for (int i = 0; i < 256; i++)
			{
				r = pal[j++] & 0xFF;
				g = pal[j++] & 0xFF;
				b = pal[j++] & 0xFF;
				
				d_8to24table[i] = (255 << 24) | (b << 16) | (g << 8) | (r << 0);
			}
			
			d_8to24table[255] &= 0x00FFFFFF; // 255 is transparent
			
			particle_t.ColorPalette = d_8to24table;
		}
		
		/*
		* GL_InitImages
		*/
		internal override void  GL_InitImages()
		{
			int i, j;
			float g = vid_gamma.value_Renamed;
			
			registration_sequence = 1;
			
			// init intensity conversions
			intensity = Cvar.Get("intensity", "2", 0);
			
			if (intensity.value_Renamed <= 1)
				Cvar.Set("intensity", "1");
			
			gl_state.inverse_intensity = 1 / intensity.value_Renamed;
			
			Draw_GetPalette();
			
			if (qglColorTableEXT)
			{
				gl_state.d_16to8table = FS.LoadFile("pics/16to8.dat");
				if (gl_state.d_16to8table == null)
					Com.Error(Defines.ERR_FATAL, "Couldn't load pics/16to8.pcx");
			}
			
			if ((gl_config.renderer & (GL_RENDERER_VOODOO | GL_RENDERER_VOODOO2)) != 0)
			{
				g = 1.0F;
			}
			
			for (i = 0; i < 256; i++)
			{
				
				if (g == 1.0f)
				{
					gammatable[i] = (sbyte) i;
				}
				else
				{
					
					//UPGRADE_WARNING: Data types in Visual C# might be different.  Verify the accuracy of narrowing conversions. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1042'"
					int inf = (int) (255.0f * System.Math.Pow((i + 0.5) / 255.5, g) + 0.5);
					if (inf < 0)
						inf = 0;
					if (inf > 255)
						inf = 255;
					gammatable[i] = (sbyte) inf;
				}
			}
			
			for (i = 0; i < 256; i++)
			{
				//UPGRADE_WARNING: Data types in Visual C# might be different.  Verify the accuracy of narrowing conversions. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1042'"
				j = (int) (i * intensity.value_Renamed);
				if (j > 255)
					j = 255;
				intensitytable[i] = (sbyte) j;
			}
		}
		
		/*
		* GL_ShutdownImages
		*/
		internal override void  GL_ShutdownImages()
		{
			image_t image;
			
			for (int i = 0; i < numgltextures; i++)
			{
				image = gltextures[i];
				
				if (image.registration_sequence == 0)
					continue; // free image_t slot
				// free it
				gl.glDeleteTextures(1, new int[]{image.texnum});
				image.clear();
			}
		}
		static Image()
		{
			{
				for (int j = 0; j < fifo.Length; j++)
				{
					fifo[j] = new floodfill_t();
				}
			}
		}
	}
}